package com.gnrsoft.rpc.client;

import com.gnrsoft.rpc.common.RpcDecoder;
import com.gnrsoft.rpc.common.RpcEncoder;
import com.gnrsoft.rpc.common.RpcRequest;
import com.gnrsoft.rpc.common.RpcResponse;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * 
 * <B>中文类名：Rpc 发送客户端</B><BR>
 * <B>概要说明：用户发送RPC请求</B><BR>
 * @author likun
 * @since 2017年7月19日
 */
public class RpcClient extends ChannelInboundHandlerAdapter{

	String host;
	int port;

	private Object object = new Object();

	RpcResponse rpcResponse;

	public RpcClient() {
	}

	public RpcClient(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public RpcResponse send(RpcRequest rpcRequest) {

		// boss 接收client连接
		EventLoopGroup bossGroup = new NioEventLoopGroup();

		try {
			Bootstrap sb = new Bootstrap();
			sb.group(bossGroup)
					// 指定 NioServerSocketChannel 通道 也就是tcp协议
					.channel(NioSocketChannel.class).option(ChannelOption.SO_KEEPALIVE, true)
					// 绑定事件处理器
					.handler(new ChannelInitializer<SocketChannel>() {
						@Override
						protected void initChannel(SocketChannel socketChannel) throws Exception {

							socketChannel.pipeline().addLast(new RpcEncoder(RpcRequest.class)); // 编码
							socketChannel.pipeline().addLast(new RpcDecoder()); // 解码
							socketChannel.pipeline().addLast(RpcClient.this);
						}
					}); 

			ChannelFuture cf = sb.connect(host, port).sync();

			//发送数据到服务器
			cf.channel().writeAndFlush(rpcRequest).sync();
			
			// 用线程等待的方式决定是否关闭连接
			synchronized (object) {
				object.wait();
			}

			if (rpcResponse != null) {
				cf.channel().closeFuture().sync(); 
			}
			return rpcResponse;

		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			bossGroup.shutdownGracefully();
		}
		return rpcResponse;

	}
	
	
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		this.rpcResponse = (RpcResponse) msg;
		
		synchronized (object) {
			object.notifyAll();
		}
		
	}
	
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		cause.printStackTrace();
		ctx.close();
	}
	
	

}
